package com.warom.sdg.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;

import com.warom.sdg.callback.DataListener;
import com.warom.sdg.callback.PlcDataListener;
import com.warom.sdg.config.MeasurementPoint;
import com.warom.sdg.config.PlcMeasurementConfig;
import com.warom.sdg.config.PlcMeasurementUtils;
import com.warom.sdg.dto.PointDataReportDto;
import com.warom.sdg.enums.ModuleType;
import com.warom.sdg.model.PlcDataEntity;
import com.warom.sdg.model.PlcDeviceEntity;
import com.warom.sdg.repository.PlcDataRepository;
import com.warom.sdg.repository.PlcDeviceRepository;
import com.warom.sdg.util.Constants;
import com.warom.sdg.util.DataReportUtil;
import com.warom.sdg.util.DeviceUtils;
import com.warom.sdg.util.GrainSituationCalculator;
import com.warom.sdg.util.HttpUtil;
import com.warom.sdg.util.JsonUtil;
import com.warom.sdg.util.LogUtils;
import com.warom.sdg.util.ModbusHelper;
import com.warom.sdg.util.ModbusTcpClient;
import com.warom.sdg.modbus.DeviceDataListener;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * PLC数据采集服务
 * 负责定时从PLC设备采集数据，并保存到数据库
 */
public class PlcDataService extends Service {
    private static final String TAG = "PlcDataService";

    // 数据更新广播
    public static final String ACTION_DATA_UPDATE = "com.warom.sdg.ACTION_DATA_UPDATE";

    // 默认轮询间隔(毫秒)
    private static final long DEFAULT_POLL_INTERVAL = 5000;
    
    // 数据仓库
    private PlcDataRepository dataRepository;
    private PlcDeviceRepository deviceRepository;

    // 粮情计算工具
    private GrainSituationCalculator grainSituationCalculator;

    // 定时任务执行器
    private ScheduledExecutorService scheduler;

    // 主线程Handler，用于回调
    private Handler mainHandler;

    // 服务绑定器
    private final IBinder binder = new PlcServiceBinder();

    // 数据监听器列表
    private List<DataListener> listeners = new ArrayList<>();

    // 轮询间隔
    private long pollInterval = DEFAULT_POLL_INTERVAL;

    // 服务运行状态
    private boolean isRunning = false;
    private Map<Integer, ModbusHelper> deviceHelperMap = new HashMap<>();

    private List<PlcDeviceEntity> currDeviceEntities = null;

    // 跟踪每个IP地址当前正在轮询的设备，以避免同IP不同端口的设备同时连接造成的通讯问题
    private Map<String, Integer> activeIpPolling = new HashMap<>();

    // 记录设备配置冲突情况
    private Set<String> conflictingDeviceConfigs = new HashSet<>();

    /**
     * PLC服务绑定器
     */
    public class PlcServiceBinder extends Binder {
        public PlcDataService getService() {
            return PlcDataService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "服务创建");

        // 初始化仓库
        dataRepository = new PlcDataRepository(this);
        deviceRepository = new PlcDeviceRepository(this);
        grainSituationCalculator = new GrainSituationCalculator(this);

        // 初始化主线程Handler
        mainHandler = new Handler(Looper.getMainLooper());

        // 创建定时任务执行器
        scheduler = Executors.newScheduledThreadPool(2);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "服务启动");

        // 如果服务已经在运行，直接返回
        if (isRunning) {
            return START_STICKY;
        }

        // 启动服务
        startService();

        // 如果服务被杀死，系统会尝试重新创建服务
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "服务绑定");
        return binder;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "服务销毁");

        // 停止服务
        stopService();

        // 清理所有设备连接
        cleanupAllConnections();

        super.onDestroy();
    }

    /**
     * 启动服务
     */
    public void startService() {
        if (isRunning) {
            return;
        }

        Log.d(TAG, "启动数据采集服务");

        // 更新运行状态
        isRunning = true;

        // 启动定时任务
        startScheduler();
    }

    /**
     * 停止服务
     */
    public void stopService() {
        if (!isRunning) {
            return;
        }

        Log.d(TAG, "停止数据采集服务");

        // 更新运行状态
        isRunning = false;

        // 停止定时任务
        stopScheduler();

        // 清理所有设备连接
        cleanupAllConnections();
    }

    /**
     * 启动定时任务
     */
    private void startScheduler() {
        // 先停止已有的定时任务
        stopScheduler();

        // 创建新的定时任务
        scheduler = Executors.newScheduledThreadPool(2);

        // 开始定时任务，定期从所有设备采集数据
        scheduler.scheduleAtFixedRate(this::pollAllDevices, 0, pollInterval, TimeUnit.MILLISECONDS);

        Log.d(TAG, "启动定时采集任务，间隔: " + pollInterval + "ms");

        // 启动粮情数据平均值计算和保存任务
        scheduler.scheduleAtFixedRate(() -> grainSituationCalculator.calculateAndSave(), 1, 5, TimeUnit.MINUTES);
        Log.d(TAG, "启动粮情数据平均值计算任务，间隔: 5分钟");
    }

    /**
     * 停止定时任务
     */
    private void stopScheduler() {
        if (scheduler != null && !scheduler.isShutdown()) {
            scheduler.shutdown();
            try {
                // 等待任务完成
                if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                    scheduler.shutdownNow();
                }
            } catch (InterruptedException e) {
                Log.e(TAG, "定时任务停止失败: " + e.getMessage());
                scheduler.shutdownNow();
            }
        }
    }

    /**
     * 轮询所有设备
     */
    private void pollAllDevices() {
        Log.d(TAG, "开始轮询所有设备...");

        // 每次轮询前清空活动IP记录
        activeIpPolling.clear();

        // 异步获取所有设备（无论是否活跃）
        deviceRepository.getAllDevices(
                devices -> {
                    // 对每个设备进行数据采集
                    this.currDeviceEntities = devices;

//                    for (PlcDeviceEntity device : devices) {
//                        pollDevice(device);
//                    }
                },
                error -> Log.e(TAG, "获取设备失败: " + error));
    }

  

    /**
     * 从单个设备采集数据
     * 
     * @param device 设备实体
     */
    private void pollDevice(PlcDeviceEntity device) {
        // 注意: 该方法在后台线程上运行，所以网络操作是安全的

        // 根据设备类型获取对应的测点配置
        int deviceTypeId = device.getDeviceTypeId();
        if (deviceTypeId <= 0) {
            deviceTypeId = 1; // 默认使用西门子S7的ID
            Log.w(TAG, "设备[" + device.getDeviceName() + "]未指定有效的设备类型，使用默认ID: " + deviceTypeId);
        }

        // 获取或创建ModbusHelper实例
        ModbusHelper modbusHelper = getModbusHelper(device);

        boolean shouldDisconnect = false; // 默认情况下保持连接不断开

        try {
            // 确保Helper已连接
            if (!modbusHelper.isConnected()) {
                boolean connected = modbusHelper.connect();
                if (!connected) {
                    Log.e(TAG, "无法连接到设备: " + device.getDeviceName());
                    updateDeviceStatus(device, false);
                    // 连接失败，这个Helper实例可能有问题，从缓存中移除
                    removeModbusHelper(device.getDeviceId());
                    return;
                }
            }

            boolean hasPoints = false;
            int successfulReads = 0; // 成功的读取次数
            int totalReads = 0; // 总读取次数

            // 遍历所有模块类型，读取所有测点数据
            for (ModuleType moduleType : PlcMeasurementUtils.getAllModuleTypes()) {
                // 获取该模块下的测点信息
                List<PlcDataEntity> moduleEntities = PlcMeasurementUtils.getMeasurementEntitiesByDeviceTypeId(
                        device.getDeviceId(),
                        deviceTypeId,
                        moduleType);

                if (!moduleEntities.isEmpty()) {
                    hasPoints = true;
                    Log.d(TAG, "设备[" + device.getDeviceName() + "]发现" + moduleEntities.size() +
                            "个" + moduleType.getDisplayName() + "测点");

                    // 遍历每个测点进行读取
                    for (PlcDataEntity entity : moduleEntities) {
                        // 如果连接中断太多次，不再继续尝试
                        if (successfulReads == 0 && totalReads >= 3) {
                            Log.e(TAG, "已尝试多次但没有成功的读取，停止采集设备[" + device.getDeviceName() + "]");
                            updateDeviceStatus(device, false);
                            // 这个Helper实例可能有问题，从缓存中移除
                            removeModbusHelper(device.getDeviceId());
                            return;
                        }

                        // 根据测点英文名称获取测点配置
                        MeasurementPoint point = PlcMeasurementUtils.getPointByEnglishName(entity.getEnglishName());
                        if (point != null) {
                            // 检查是否需要更新该测点数据
                            if (!point.shouldUpdate()) {
                                Log.d(TAG, "跳过测点 " + entity.getName() + "，未到更新时间");
                                continue;
                            }
                        }

                        String address = entity.getAddress();
                        Log.d(TAG, "读取" + moduleType.getDisplayName() + "测点: " +
                                entity.getName() + ", 地址: " + address);

                        // 确保连接状态
                        if (!modbusHelper.isConnected()) {
                            Log.d(TAG, "读取之前发现连接已断开，尝试重新连接");
                            boolean reconnected = modbusHelper.getModbusTcpClient().keepAlive();
                            if (!reconnected) {
                                Log.e(TAG, "无法恢复连接，跳过该测点: " + entity.getName());
                                // 无法重连，Helper可能有问题，标记为需要重新创建
                                shouldDisconnect = true;
                                continue;
                            }
                        }

                        // 读取地址
                        totalReads++;
                        boolean success = false;

                        System.out.println(PlcMeasurementConfig.moduleDevicePointsMap);
                        try {
                            success = modbusHelper.readAddress(address, 1, device.getUnitId());
                        } catch (Exception e) {
                            Log.e(TAG, "读取地址时发生异常: " + e.getMessage(), e);
                        }

                        if (success) {
                            successfulReads++;
                            // 注意：不再在这里更新最后读取时间，而是在DeviceDataListener中处理
                        } else {
                            Log.w(TAG, "读取地址失败: " + address);
                        }
                    }
                }
            }

            if (!hasPoints) {
                Log.w(TAG, "设备[" + device.getDeviceName() + "]未配置任何测点");
            }

            // 根据读取结果更新设备状态
            boolean deviceActive = (totalReads > 0 && successfulReads > 0);
            updateDeviceStatus(device, deviceActive);

            // 如果存在严重的连接问题，需要重新创建Helper
            if (totalReads > 0 && successfulReads == 0) {
                Log.w(TAG, "设备[" + device.getDeviceName() + "]读取全部失败，将重新创建连接");
                shouldDisconnect = true;
            }

        } catch (Exception e) {
            Log.e(TAG, "从设备[" + device.getDeviceName() + "]采集数据失败: " + e.getMessage(), e);

            // 更新设备状态为不活跃
            updateDeviceStatus(device, false);
            // 发生异常，标记为需要重新创建Helper
            shouldDisconnect = true;
        } finally {
            // 根据情况决定是否断开连接并从缓存中移除
            if (shouldDisconnect) {
                try {
                    Log.d(TAG, "设备[" + device.getDeviceName() + "]连接问题，断开并从缓存移除");
                    modbusHelper.disconnect();
                    removeModbusHelper(device.getDeviceId());
                } catch (Exception e) {
                    Log.w(TAG, "断开连接时出错: " + e.getMessage());
                }
            }
        }
    }

    /**
     * 获取设备对应的ModbusHelper实例
     * 如果不存在则创建新的实例
     * 
     * @param device 设备实体
     * @return ModbusHelper实例
     */
    private ModbusHelper getModbusHelper(PlcDeviceEntity device) {
        // 从缓存中获取
        ModbusHelper helper = deviceHelperMap.get(device.getDeviceId());

        // 如果不存在或连接已断开，创建新的
        if (helper == null) {
            Log.d(TAG, "为设备[" + device.getDeviceName() + "]创建新的ModbusHelper实例");
            helper = new ModbusHelper(device.getDeviceIp(), device.getDevicePort(),
                    new DeviceDataListener(device, this));

            // 设置更长的超时时间并启用自动重连
            helper.setTimeout(5000); // 5秒超时
            helper.getModbusTcpClient().setAutoReconnect(true);

            // 添加到缓存
            deviceHelperMap.put(device.getDeviceId(), helper);
        } else {
            // 如果IP或端口发生变化，需要重新创建
            boolean needRebuild = false;

            if (!helper.getModbusTcpClient().getIpAddress().equals(device.getDeviceIp())) {
                Log.d(TAG, "设备[" + device.getDeviceName() + "]IP地址已变更，需要重新创建连接");
                needRebuild = true;
            }

            if (helper.getModbusTcpClient().getPort() != device.getDevicePort()) {
                Log.d(TAG, "设备[" + device.getDeviceName() + "]端口已变更，需要重新创建连接");
                needRebuild = true;
            }

            if (needRebuild) {
                // 断开旧连接
                helper.disconnect();

                // 创建新实例
                helper = new ModbusHelper(device.getDeviceIp(), device.getDevicePort(),
                        new DeviceDataListener(device, this));

                // 设置参数
                helper.setTimeout(8000);
                helper.getModbusTcpClient().setAutoReconnect(true);

                // 更新缓存
                deviceHelperMap.put(device.getDeviceId(), helper);
            }
        }

        return helper;
    }

    /**
     * 从缓存中移除ModbusHelper实例
     * 
     * @param deviceId 设备ID
     */
    private void removeModbusHelper(int deviceId) {
        ModbusHelper helper = deviceHelperMap.remove(deviceId);
        if (helper != null) {
            try {
                helper.disconnect();
                Log.d(TAG, "已从缓存中移除设备ID[" + deviceId + "]的ModbusHelper实例");
            } catch (Exception e) {
                Log.w(TAG, "断开移除的ModbusHelper连接时出错: " + e.getMessage());
            }
        }
    }

    /**
     * 清理所有设备连接
     * 在服务停止时调用
     */
    private void cleanupAllConnections() {
        Log.d(TAG, "清理所有设备连接，共" + deviceHelperMap.size() + "个连接");

        for (Map.Entry<Integer, ModbusHelper> entry : deviceHelperMap.entrySet()) {
            try {
                ModbusHelper helper = entry.getValue();
                if (helper != null) {
                    helper.disconnect();
                    Log.d(TAG, "已断开设备ID[" + entry.getKey() + "]的连接");
                }
            } catch (Exception e) {
                Log.w(TAG, "断开设备ID[" + entry.getKey() + "]连接时出错: " + e.getMessage());
            }
        }

        deviceHelperMap.clear();
    }

    /**
     * 更新设备状态
     * 
     * @param device   设备实体
     * @param isActive 是否活跃
     */
    public void updateDeviceStatus(PlcDeviceEntity device, boolean isActive) {
        // 如果状态没变，不更新
        if (device.isActive() == isActive) {
            return;
        }

        // 更新状态
        device.setActive(isActive);
        device.setLastConnectTime(System.currentTimeMillis());

        // 保存到数据库
        deviceRepository.update(device, null, error -> Log.e(TAG, "更新设备状态失败: " + error));
    }

    /**
     * 注册数据监听器
     * 
     * @param listener 监听器
     */
    public void registerListener(DataListener listener) {
        if (listener != null && !listeners.contains(listener)) {
            listeners.add(listener);
        }
    }

    /**
     * 注销数据监听器
     * 
     * @param listener 监听器
     */
    public void unregisterListener(DataListener listener) {
        if (listener != null) {
            listeners.remove(listener);
        }
    }

    /**
     * 保存采集的数据
     * 
     * @param deviceId 设备ID
     * @param name     数据名称
     * @param address  寄存器地址
     * @param type     数据类型
     * @param value    数据值
     * @param unit     单位
     */
    public void saveData(Integer deviceId, String name, String address, String type, String value, String unit) {
        // 创建数据实体
        PlcDataEntity data = new PlcDataEntity();
        data.setDeviceId(deviceId);
        data.setName(name);
        data.setAddress(address);
        data.setType(type);
        data.setValue(value);
        data.setUnit(unit);
        data.setTimestamp(System.currentTimeMillis());

        // 保存到数据库
        dataRepository.insert(data,
                // 成功后触发回调
                () -> notifyDataChanged(data),
                // 错误处理
                error -> Log.e(TAG, "保存数据失败: " + error));
    }

    /**
     * 通知数据变化
     * 
     * @param data 数据实体
     */
    private void notifyDataChanged(final PlcDataEntity data) {
        if (listeners.isEmpty()) {
            return;
        }

        // 在主线程中回调
        mainHandler.post(() -> {
            for (DataListener listener : listeners) {
                listener.onDataReceived(data);
            }
        });
    }

    /**
     * 批量保存PLC数据实体
     * 
     * @param entities 数据实体列表
     */
    public void saveDataBatch(List<PlcDataEntity> entities) {
        if (entities == null || entities.isEmpty()) {
            Log.w(TAG, "保存批量数据: 数据为空");
            return;
        }

        Log.i(TAG, "批量保存数据: " + entities.size() + " 条记录");

        try {
            for (PlcDataEntity entity : entities) {
                // 使用现有的saveData方法保存每个数据点
                saveData(
                        entity.getDeviceId(),
                        entity.getName(),
                        entity.getAddress(),
                        "",
                        entity.getValue(),
                        entity.getUnit());
            }
            Log.i(TAG, "批量保存数据成功");
        } catch (Exception e) {
            Log.e(TAG, "批量保存数据失败", e);
        }
    }

    /**
     * 上报数据到后台服务器
     * 
     * @param device           设备实体
     * @param measurementPoint 测点配置
     * @param value            数据值
     */
    private void reportDataToServer(PlcDeviceEntity device, MeasurementPoint measurementPoint,
            float value) {
        try {
            // 使用工具类创建数据上报DTO对象
            PointDataReportDto reportDto = DataReportUtil.createDataReportDto(
                    getApplicationContext(), device, measurementPoint, value);

            // 使用工具类异步上报数据
            DataReportUtil.reportDataAsync(reportDto);
        } catch (Exception e) {
            Log.e(TAG, "准备上报数据时出错: " + e.getMessage(), e);
        }
    }

    /**
     * 写入地址
     * 根据设备ID和地址写入值
     * 
     * @param deviceId 设备ID
     * @param address  地址
     * @param value    值
     */
    public boolean writeAddress(String deviceId, String address, int value) {
        try {
            // 将字符串设备ID转换为整数
            int deviceIdInt = Integer.parseInt(deviceId);

            // 直接从缓存获取ModbusHelper
            PlcDeviceEntity device = getByDeviceIdFromCache(deviceId);
            if (device == null) {
                Log.e(TAG, "未找到设备ID: " + deviceId + " 的设备，无法写入数据");
                return false;
            }
            ModbusHelper helper = deviceHelperMap.get(device.getDeviceId());
            if (helper == null) {
                helper = getModbusHelper(device);
                deviceHelperMap.put(device.getDeviceId(), helper);
            }
            if (helper != null) {
                // 直接写入数据
                helper.writeAddress(address, value, device.getUnitId());
                Log.i(TAG, "写入指令已发送 - 设备ID: " + deviceIdInt + ", 地址: " + address + ", 值: " + value);
                return true;

            } else {
                Log.e(TAG, "未找到设备ID: " + deviceIdInt + " 的ModbusHelper，无法写入数据");
            }
        } catch (Exception e) {
            Log.e(TAG, "写入数据时发生异常: " + e.getMessage(), e);
            return false;
        }
        return false;
    }

    private PlcDeviceEntity getByDeviceIdFromCache(String deviceId) {
        if (currDeviceEntities != null && currDeviceEntities.size() > 0) {
            for (PlcDeviceEntity device : currDeviceEntities) {
                if (device.getDeviceId() == Integer.parseInt(deviceId)) {
                    return device;
                }
            }
        }
        return null;
    }
}